﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;

namespace Client
{
    public partial class chat : Form
    {
        /* Clipboard */
        [DllImport("User32.dll")]
        protected static extern int SetClipboardViewer(int hWndNewViewer);

        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);

        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

        private IntPtr nextClipboardViewer;
        private string richClip = "";
        protected TcpClient sClip = new TcpClient();
        protected Stream sClipStream;
        protected byte[] bufClip, sendClip;
        protected byte[] clipType = new byte[4];
        private String clipTypeS = "";
        private int bufLen;
        private UInt16 portaClip;
        private IPAddress ipAddr;
        private int cont = 0;
        private Object oggClip = new Object();
        private bool ctrlClip = false;
        String[] filenameIn = new String[1];
        String[] filenameOut = new String[1];
        public delegate void settaClip(bool value);
        public settaClip setClip;

        /* *********** */

        private const int DIM = 1024;
        protected video myVideo;
        private Thread receiver, receiverClip;
        private String User, other;
        private Stream sChat;
        public delegate void msg(string s);
        public delegate void close();
        private msg writemsg;
        private close exit;
        // per disabilitare il tasto X del form
        private const int CP_NOCLOSE_BUTTON = 0x200;

        public chat(StartClient cliente, String clip_port)
        {
            InitializeComponent();
            User = cliente.getUser; UtenteConnesso.Text = User;
            byte[] tmp = new byte[DIM];
            sChat = cliente.getTCP.GetStream();
            int l = sChat.Read(tmp, 0, DIM);
            other = System.Text.Encoding.ASCII.GetString(tmp);
            other = other.Substring(0, l);
            writemsg = new msg(addMsg);
            exit = new close(chiudi);
            receiver = new Thread(receive);
            chatBox.AppendText("Connected with: ");
            chatBox.AppendText(other);
            receiver.Start();
            /* Clipboard */
            ClipboardButton.Enabled = false;
            nextClipboardViewer = (IntPtr)SetClipboardViewer((int)this.Handle);
            portaClip = UInt16.Parse(clip_port);
            ipAddr = cliente.getIP;
            setClip = new settaClip(settaButt);
            filenameIn[0] = "";
            filenameOut[0] = "";
            Clipboard.Clear();
            try
            {
                sClip.Connect(ipAddr, portaClip);
                sClipStream = sClip.GetStream();
                receiverClip = new Thread(receiveClip);
                receiverClip.SetApartmentState(ApartmentState.STA);
                receiverClip.Start();
            }
            catch
            {
                MessageBox.Show("Connection clipboard failure... Try later");
            }
        }

        private void settaButt(bool abilt)
        {
            ClipboardButton.Enabled = abilt;
        }

        public TcpClient getSClipCon
        {
            get { return sClip; }
        }

        public void addMsg(string str)
        {
            chatBox.AppendText(str);
        }

        public Thread recvClip
        {
            get { return receiverClip; }
        }

        public void getStringPrint(String message)
        {
            chatBox.AppendText(message + Environment.NewLine);
        }
        
        private void SendMessage_Click(object sender, EventArgs e)
        {
            if (!messageChat.Text.Equals(""))
            {
                try
                {
                    byte[] msg = new byte[DIM];
                    sChat.Write(Encoding.ASCII.GetBytes(messageChat.Text.ToCharArray()), 0, messageChat.Text.Length);
                    chatBox.AppendText(Environment.NewLine + "<" + User + ">: ");
                    chatBox.AppendText(messageChat.Text);
                    messageChat.Text = "";
                }
                catch
                {
                    chatBox.AppendText("Error Sending message!" + Environment.NewLine);
                    messageChat.Text = "";
                }
            }
        }

        private void receive()
        {
            string str;
            bool uscita = false;
            byte[] buf = new byte[DIM];
            try
            {
                while (!uscita)
                {
                    int ln = sChat.Read(buf, 0, DIM);
                    if (ln != 0)
                    {
                        buf[ln] = 0;
                        str = System.Text.Encoding.ASCII.GetString(buf).Substring(0, ln);
                        if (str.Length != 0)
                        {
                            str = Environment.NewLine + str;
                            Invoke(writemsg, str);
                        }
                    }
                    else
                    {
                        uscita = true;
                    }
                }
            }
            catch
            {
                ;
            }    
            finally
            {
                String str2 = Environment.NewLine + "Disconnected";
                try
                {
                    Invoke(writemsg, str2);
                }
                catch { ;}
                receiver.Abort();
                Application.ExitThread();
            }
        }

        private void chiudi()
        {
            this.Close();
        }

        private void receiveClip()
        {
            int ln, clipDim;
            byte[] dimClip = new byte[4];
            BinaryReader stream = new BinaryReader(sClipStream);
            bool uscita = false;
            try
            {
                while (!uscita)
                {
                    try
                    {
                        ln = sClipStream.Read(clipType, 0, 4);
                        if (ln != 0)
                        {
                            String cod = System.Text.Encoding.ASCII.GetString(clipType);
                            cod = cod.Substring(0, 4);
                            clipDim = stream.ReadInt32();
                            bufClip = stream.ReadBytes(clipDim);
                            Monitor.Enter(oggClip);
                            ctrlClip = true;
                            Object o = new Object();
                            if (File.Exists(filenameIn[0]))
                            {
                                File.Delete(filenameIn[0]);
                            }
                            if (cod.Equals("Text"))
                            {
                                o = ByteArrayToObject(bufClip);
                                Clipboard.SetData(DataFormats.Text, o);
                            }
                            else
                            {
                                if (cod.Equals("Bitm"))
                                {
                                    o = ByteArrayToObject(bufClip);
                                    Clipboard.SetData(DataFormats.Bitmap, o);
                                }
                                if (cod.Equals("File"))
                                {
                                    o = ByteArrayToObject(bufClip); byte[] temp;
                                    filenameIn = (String[])o;
                                    filenameIn[0] = Path.GetFileName(filenameIn[0]);
                                    filenameIn[0].Replace("\\", "\\\\");
                                    using (FileStream fs = new FileStream(@filenameIn[0], FileMode.OpenOrCreate, FileAccess.Write))
                                    {
                                        long fileLen = stream.ReadInt64();
                                        int letti = DIM;
                                        temp = new byte[DIM];
                                        for (long k = 0; k < fileLen || letti == 0; k += letti)
                                        {
                                            letti = sClipStream.Read(temp, 0, DIM);
                                            fs.Write(temp, 0, letti);
                                        }
                                    }
                                    filenameIn[0] = Path.GetFullPath(@filenameIn[0]);
                                    filenameIn[0].Replace("\\", "\\\\");
                                    System.Collections.Specialized.StringCollection tmpColl = new System.Collections.Specialized.StringCollection();
                                    tmpColl.Add(filenameIn[0]);
                                    Clipboard.SetFileDropList(tmpColl);
                                    MessageBox.Show("New File in Clipboard!\nPress OK to skip - Ctrl+V to paste", "New File in Clipboard");
                                }
                            }
                            Invoke(setClip, false);
                            Monitor.Exit(oggClip);
                            ctrlClip = false;
                        }
                        else
                        {
                            uscita = true;
                        }
                    }
                    catch 
                    {
                        ;
                    }
                }
            }
            catch 
            {
                ;
            }
            finally
            {
                if (ctrlClip)
                {
                    try
                    {
                        Monitor.Exit(oggClip);
                    }
                    catch
                    {
                        ;
                    }
                } 
                if (File.Exists(filenameIn[0]))
                {
                    File.Delete(filenameIn[0]);
                }
                Application.ExitThread();
            }
            
        }

        public object ByteArrayToObject(byte[] _ByteArray)
        {
            try
            {
                MemoryStream _MemoryStream = new MemoryStream();
                BinaryFormatter _BinaryFormatter = new BinaryFormatter();
                _MemoryStream.Write(_ByteArray, 0, _ByteArray.Length);
                _MemoryStream.Seek(0, SeekOrigin.Begin);
                return (Object)_BinaryFormatter.Deserialize(_MemoryStream);
            }
            catch
            {
                ;
            }
            return null;
        }

        protected override void WndProc(ref Message msg)
        {
            const int WM_DRAWCLIPBOARD = 0x308;
            const int WM_CHANGECBCHAIN = 0x030D;

            switch (msg.Msg)
            {
                case WM_DRAWCLIPBOARD:
                    SendMessage(nextClipboardViewer, msg.Msg, msg.WParam, msg.LParam);
                    if (cont < 2)
                        cont++;
                    else
                        ClipboardButton.Enabled = true;
                    break;

                case WM_CHANGECBCHAIN:
                    if (msg.WParam == nextClipboardViewer)
                        nextClipboardViewer = msg.LParam;
                    else
                        SendMessage(nextClipboardViewer, msg.Msg, msg.WParam, msg.LParam);
                    break;

                default:
                    base.WndProc(ref msg);
                    break;
            }
        }

        void DisplayClipboardData()
        {
            try
            {
                Object Data = new Object();
                MemoryStream memStream = new MemoryStream();
                BinaryFormatter binFormatter = new BinaryFormatter();

                if (Clipboard.ContainsText())
                {
                    richClip = "Text- Text in Clipboard";
                    Data = Clipboard.GetData(DataFormats.Text);
                    clipTypeS = "Text";
                }
                else
                {
                    if (Clipboard.ContainsFileDropList())
                    {
                        richClip = "File- File in Clipboard";
                        Data = Clipboard.GetData(DataFormats.FileDrop);
                        filenameOut = (String[])Data;
                        clipTypeS = "File";
                    }
                    if (Clipboard.ContainsImage())
                    {
                        richClip = "Bitm- Bitmap in Clipboard";
                        Data = Clipboard.GetData(DataFormats.Bitmap);
                        clipTypeS = "Bitm";
                    }
                }
                binFormatter.Serialize(memStream, Data);
                sendClip = memStream.ToArray();
                bufLen = sendClip.Length;
            }
            catch
            {
                MessageBox.Show("ClipBoard Error!\nRetry to press clipboard button!");
            }
        }

        private void ClipboardButton_Click(object sender, EventArgs e)
        {
            DisplayClipboardData();
            if (!richClip.Equals(""))
            {
                try
                {
                    sChat.Write(Encoding.ASCII.GetBytes(richClip.ToCharArray()), 0, richClip.Length);
                    chatBox.AppendText(Environment.NewLine + "<" + User + ">: ");
                    chatBox.AppendText(richClip);
                    sClipStream.Write(Encoding.ASCII.GetBytes(clipTypeS.ToCharArray()), 0, clipTypeS.Length);
                    byte[] tmp2 = BitConverter.GetBytes(bufLen);
                    sClipStream.Write(tmp2, 0, 4);
                    sClipStream.Write(sendClip, 0, bufLen);
                    sClipStream.Flush();
                    if (clipTypeS.Equals("File"))
                    {
                        byte[] temp;
                        filenameOut[0] = Path.GetFullPath(filenameOut[0]);
                        filenameOut[0].Replace("\\", "\\\\");
                        using (FileStream fs = new FileStream(filenameOut[0], FileMode.Open, FileAccess.Read))
                        {
                            long fileLen = fs.Length;
                            int letti = DIM;
                            temp = new byte[DIM];
                            byte[] tmp64 = BitConverter.GetBytes(fileLen);
                            sClipStream.Write(tmp64, 0, 8);
                            for (long k = 0; k < fileLen || letti == 0; k += letti)
                            {
                                letti = fs.Read(temp, 0, DIM);
                                sClipStream.Write(temp, 0, letti);
                            }
                        }
                    }
                }
                catch 
                {
                    chatBox.AppendText(Environment.NewLine + "Error Sending clipboard!");
                }
                richClip = "";
                ClipboardButton.Enabled = false;
            }
        }

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams myCp = base.CreateParams;
                myCp.ClassStyle = myCp.ClassStyle | CP_NOCLOSE_BUTTON;
                return myCp;
            }
        }
    }
}
